package com.example.trb.controller.file;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.example.trb.util.UUIDUtil;
import com.example.trb.util.result.CommonResult;
import com.example.trb.util.result.SysReturnCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

@RestController
@Slf4j
public class FileUploadController {
    @Value("${file.upload.url}")
    String uploadFilePath;
    @Value("${bucketName}")
    String bucketName;
    @Value("${accessKeySecret}")
    String accessKeySecret;
    @Value("${endpoint}")
    String endpoint;
    @Autowired
    ExecutorService taskExecutor;
    @Value("${max_size_file_upload}")
    Integer maxSizeFileUpload;
    @Value("${accessKeyId}")
    private String accessKeyId;

    @PostMapping(path = "/upload", consumes = {"multipart/form-data"})
    public CommonResult upload(@RequestParam("files") MultipartFile files[]) {
        if (files.length > maxSizeFileUpload) {
            SysReturnCode code = SysReturnCode.BAD_REQUEST;
            return CommonResult.fail(code.code, "上传的文件太多了");
        }

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        List<String> urls = new ArrayList<>(files.length);
        List<Future<String>> futures = new ArrayList<>(files.length);

        for (int i = 0; i < files.length; i++) {
            MultipartFile file = files[i];
            Callable<String> callable = () -> {
                String filename = file.getOriginalFilename();
                String[] split = filename.split("\\.");

                String fileType = "." + split[split.length - 1]; // 获取文件类型
                String objectName = uploadFilePath + UUIDUtil.uuid() + fileType;  // 文件上传路径
                String url = String.format("https://%s.%s/%s", bucketName, endpoint, objectName); // 拼接返回的url
                ossClient.putObject(bucketName, objectName, file.getInputStream()); // 上传文件
                return url;
            };
            futures.add(taskExecutor.submit(callable));
        }

        int failCount = 0;
        try {
            for (int i = 0; i < files.length; i++) {
                try {
                    Future<String> future = futures.get(i);
                    urls.add(future.get());
                } catch (OSSException | InterruptedException | ExecutionException e) {
                    if (e instanceof ExecutionException) {
                        Throwable cause = e.getCause();
                        log.info("a file upload fail, message: " + cause.getMessage());
                    } else {
                        log.info("a file upload fail, message: " + e.getMessage());
                    }
                    failCount++;
                } catch (ClientException ce) {
                    log.info("a file upload fail, because client encounter error, message: " + ce.getMessage());
                    SysReturnCode code = SysReturnCode.REQUEST_TIMEOUT;
                    for (int j = 0; j < futures.size(); j++)
                        futures.get(i).cancel(true);
                    return CommonResult.fail(code.code, "上传失败，可能出现了网络问题，请检查网络状况后重试");
                }
            }
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        if (failCount == 0)
            return CommonResult.common(SysReturnCode.OK.code(), "上传成功", urls);
        else
            return CommonResult.common(SysReturnCode.OK.code(), "有" + failCount + "个文件上传失败", urls);
    }

    @PostMapping(path = "/upload/test", consumes = {"multipart/form-data"})
    public CommonResult uploadTest(@RequestParam("files") MultipartFile files[]){
        if (files.length > maxSizeFileUpload) {
            SysReturnCode code = SysReturnCode.BAD_REQUEST;
            return CommonResult.fail(code.code, "上传的文件太多了");
        }

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        List<String> urls = new ArrayList<>(files.length);

        for (MultipartFile file : files) {
            String filename = file.getOriginalFilename();
            String[] split = filename.split("\\.");

            String fileType = "." + split[split.length - 1]; // 获取文件类型
            String objectName = uploadFilePath + UUIDUtil.uuid() + fileType;  // 文件上传路径
            String url = String.format("https://%s.%s/%s", bucketName, endpoint, objectName); // 拼接返回的url
            try {
                ossClient.putObject(bucketName, objectName, file.getInputStream()); // 上传文件
            } catch (IOException e) {

            } finally {
                if (ossClient != null)
                    ossClient.shutdown();
            }

            urls.add(url);
        }

        return CommonResult.common(SysReturnCode.OK.code(), "上传成功", urls);
    }
}
